package com.runjian.rundo.iot.agent.iec104.parser;

import org.springframework.stereotype.Component;

import com.runjian.rundo.iot.agent.iec104.enums.UFrameControlType;
import com.runjian.rundo.iot.agent.iec104.parser.frame.*;

import cn.hutool.core.util.ByteUtil;
import lombok.RequiredArgsConstructor;

/**
 * APCI解析器
 *
 * @author CaoQingHua
 */
@Component
@RequiredArgsConstructor
class APCIParser implements Parser {

    private final ASDUParser asduParser;

    @Override
    public AIec104Frame analysis(byte[] msg) throws ParserException {
        short b_1 = (short)(msg[2] & 0xff);
        short b_3 = (short)(msg[4] & 0xff);
        // 根据控制域判断报文类型
        if ((b_1 & 0x01) == 0 && (b_3 & 0x01) == 0) {
            // I帧
            return analysisI(msg);
        } else if ((b_1 & 0x03) == 1 && (b_3 & 0x01) == 0) {
            // S帧
            return analysisS(msg);
        } else if ((b_1 & 0x03) == 3 && (b_3 & 0x01) == 0) {
            // U帧
            return analysisU(msg);
        }
        return null;
    }

    /**
     * 解析I侦
     * 
     * @param msg 内容消息体
     * @return I侦框架
     * @throws ParserException
     */
    public IIec104Frame analysisI(byte[] msg) throws ParserException {
        //new byte[]{msg[2], msg[3]}) >> 1的意思是：从msg数组中取出第三个字节和第四个字节，将它们转换为一个short类型的数值，然后将这个数值右移1位，以获取正确的发送序列号
        short sendNo = (short) (ByteUtil.bytesToShort(new byte[]{msg[2], msg[3]}) >> 1);
        short receiveNo = (short) (ByteUtil.bytesToShort(new byte[]{msg[4], msg[5]}) >> 1);
        IIec104Frame frame = IIec104Frame.builder().sendNo(sendNo)
                .receiveNo(receiveNo).build();
        // 解析ASDU包装
        try {
            ASDUFrame asdu = asduParser.analysis(msg);
            frame.setAsdu(asdu);
            return frame;
        } catch (Exception e) {
            throw new ParserException("解析I帧出现错误: " + e);
        }
    }

    /**
     * 解析S侦
     * 
     * @param msg 内容体
     * @return 返回S侦框架
     */
    public SIec104Frame analysisS(byte[] msg) {
        short receiveNo = (short)(ByteUtil.bytesToShort(new byte[] {msg[4], msg[5]}) >> 1);
        SIec104Frame frame = new SIec104Frame();
        frame.setReceiveNo(receiveNo);
        return frame;
    }

    /**
     * 解析U侦
     * 
     * @param msg 内容体
     * @return 返回U侦框架
     */
    public UIec104Frame analysisU(byte[] msg) {
        UIec104Frame uIec104Frame = new UIec104Frame();
        short b_1 = (short)((msg[2] & 0xff) >> 2);
        switch (b_1) {
            case 1:
                uIec104Frame.setFunction(UFrameControlType.STARTDT_C);
                break;
            case 2:
                uIec104Frame.setFunction(UFrameControlType.STARTDT_V);
                break;
            case 4:
                uIec104Frame.setFunction(UFrameControlType.STOPDT_C);
                break;
            case 8:
                uIec104Frame.setFunction(UFrameControlType.STOPDT_V);
                break;
            case 16:
                uIec104Frame.setFunction(UFrameControlType.TESTFR_C);
                break;
            case 32:
                uIec104Frame.setFunction(UFrameControlType.TESTFR_V);
                break;
        }
        return uIec104Frame;
    }
}
